﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;

using System.Text;
using System.Windows.Forms;
using Firefly.Data;

namespace Firefly.Forms {
    public partial class WorldEditorForm : Form {
        // Disables editing of world variables.
        public bool FormEnabled {
            get { return this.splitContainer1.Panel2.Enabled; }
            set { this.splitContainer1.Panel2.Enabled = value; }
        }

        public int SelectedWorld { get; set; }

        // If the value is null, the world was deleted. :D
        public List<WorldConfig> WorldList { get; private set; }
        public List<WorldConfig> OldWorldList { get; private set; }

        public WorldEditorForm() {
            InitializeComponent();
            LoadFormData();
            RefreshForm();
        }

        /// <summary>
        /// THIS FORM IS NOT ALLOWED TO DISPOSE. STOP TRYING, DAMMIT.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosing(CancelEventArgs e) {
            e.Cancel = true;
            this.Hide();
            WorldSelectorForm wsf = (WorldSelectorForm)Program.WindowManager.Forms["World Selector"];
            wsf.LoadAvailableWorlds();
            LoadFormData();
            RefreshForm();
        }
       
        /// <summary>
        /// Populates all form data and world list.
        /// </summary>
        public void LoadFormData() {
            this.WorldList = new List<WorldConfig>();
            this.OldWorldList = new List<WorldConfig>();
            // Load the worlds.
            // Also populate the listbox.
            foreach (string s in WorldFile.GetWorldList()) 
                this.WorldList.Add( WorldFile.Load(s));
            // Backup the world list for comparison later.
            this.OldWorldList = this.WorldList;
        }

        /// <summary>
        /// Refreshes the world list.
        /// </summary>
        public void RefreshWorldList() {
            this.listBox1.Items.Clear();
            if (WorldList.Count > 0) {
                foreach (WorldConfig wc in WorldList)
                    if (wc != null)
                        this.listBox1.Items.Add(wc.WorldName);
                this.listBox1.SelectedIndex = SelectedWorld;
            }
        }

        /// <summary>
        /// Refreshes the form based on WorldList data.
        /// </summary>
        public void RefreshForm() {
            ClearForm();

            RefreshWorldList();

            if (WorldList.Count > 0) {
                RefreshCharacterList();
                listBox1.SelectedIndex = SelectedWorld; // Set the listbox index.
                textBoxWorldName.Text = WorldList[SelectedWorld].WorldName;
                textBoxServerAddress.Text = WorldList[SelectedWorld].ServerAddress;
                textBoxServerPort.Text = WorldList[SelectedWorld].ServerPort.ToString();
                textBoxBackupAddress.Text = WorldList[SelectedWorld].BackupAddress;
                textBoxBackupPort.Text = WorldList[SelectedWorld].BackupPort.ToString();
                textBoxProxyHost.Text = WorldList[SelectedWorld].ProxyAddress;
                textBoxProxyPort.Text = WorldList[SelectedWorld].ProxyPort.ToString();
                checkBoxUnhidePasswords.Checked = false;
                checkBoxUseProxy.Checked = WorldList[SelectedWorld].UsingProxy;
            }
        }

        public void RefreshCharacterList() {
            if (checkBoxUnhidePasswords.Checked) {
                dataGridView1.Rows.Clear();
                foreach (Character c in WorldList[SelectedWorld].Characters) {
                    dataGridView1.Rows.Add(new string[] {
                    c.Name,
                    c.Password
                });
                }
                textBoxCharacterPassword.UseSystemPasswordChar = false;
            } else {
                dataGridView1.Rows.Clear();
                foreach (Character c in WorldList[SelectedWorld].Characters) {
                    string password = String.Empty;
                    dataGridView1.Rows.Add(new string[] {
                    c.Name,
                    password.PadLeft(c.Password.Length,'*')
                });
                }
                textBoxCharacterPassword.UseSystemPasswordChar = true;
            }
        }

        public void ClearForm() {
            textBoxWorldName.Text = String.Empty;
            textBoxServerAddress.Text = String.Empty;
            textBoxServerPort.Text = String.Empty;
            textBoxBackupAddress.Text = String.Empty;
            textBoxBackupPort.Text = String.Empty;
            textBoxCharacterName.Text = String.Empty;
            textBoxCharacterPassword.Text = String.Empty;
            textBoxProxyHost.Text = String.Empty;
            textBoxProxyPort.Text = String.Empty;
            textBoxStartupCommands.Text = String.Empty;
            checkBoxUnhidePasswords.Checked = false;
            checkBoxAutoConnect.Checked = false;
            checkBoxDefaultCharacter.Checked = false;
            checkBoxUseProxy.Checked = false;
            dataGridView1.RowCount = 0;
            listBox1.Items.Clear();
        }

        /// <summary>
        /// Saves all changes made to worlds while in the editor.
        /// Also deletes files that no longer exist.
        /// </summary>
        public void SaveChanges() {
            CacheChanges();

            int index = 0;
            foreach (WorldConfig wc in WorldList) {
                if (wc == null && index < OldWorldList.Count - 1) {// This file was deleted?
                    WorldFile.Delete(OldWorldList[index].WorldName);
                } else {
                    WorldFile.Save(wc);
                    Console.WriteLine("World " + wc.WorldName + ": saving " + wc.Characters.Count + " characters.");
                }
            }
        }

        public void CacheChanges() {
            if (WorldList.Count > 0 && WorldList[SelectedWorld].ChangesMade) {
                this.WorldList[SelectedWorld].WorldName = textBoxWorldName.Text;
                this.WorldList[SelectedWorld].ServerAddress = textBoxServerAddress.Text;
                this.WorldList[SelectedWorld].ServerPort = Convert.ToInt32(textBoxServerPort.Text);
                this.WorldList[SelectedWorld].BackupAddress = textBoxBackupAddress.Text;
                this.WorldList[SelectedWorld].BackupPort = Convert.ToInt32(textBoxBackupPort.Text);
                this.WorldList[SelectedWorld].UsingProxy = checkBoxUseProxy.Checked;
                this.WorldList[SelectedWorld].ChangesMade = true;
            }
        }

        public void OpenWorld(string p) {
            // If there are changes, save them.
            CacheChanges();

            int index=0;
            foreach (WorldConfig wc in WorldList)
                if (wc.WorldName == p)
                    SelectedWorld = index;
                else
                    index++;
            // Refresh the form! Duh.
            RefreshForm();
            // Enable form for editing.
            FormEnabled = true;
        }

        public void OpenWorld() {
            // If there are changes, save them.
            CacheChanges();

            int index = 0;
            while (listBox1.Items.Contains("New World " + index)) // Find a free number.
                index++;
            // Create the world
            WorldList.Add(new WorldConfig() { WorldName = "New World " + index });
            // Set the index
            this.SelectedWorld = this.WorldList.Count - 1;
            // Refresh the form! Duh.
            RefreshForm();
            // Enable form for editing.
            FormEnabled = true;
        }

        /// <summary>
        /// Returns the world config from the world config list.
        /// </summary>
        /// <param name="p"></param>
        public WorldConfig GetWorld(string p) {
            foreach (WorldConfig wc in WorldList)
                if (wc.WorldName == p)
                    return wc;
                    return null; // Found nothing.
        }

        public int GetWorldIndex(string p) {
            int index = 0;
            foreach (WorldConfig wc in WorldList)
                if (wc != null && wc.WorldName == p)
                    return index;
                else
                    index++;
            return index;
        }

        #region Events
        private void listBox1_MouseClick(object sender, MouseEventArgs e) {
            // If there are changes. Save them.
            CacheChanges();
            if (listBox1.SelectedItem != null)
                OpenWorld((string)listBox1.SelectedItem);
        }

        private void buttonCreateWorld_Click(object sender, EventArgs e) {
            OpenWorld();
        }

        private void buttonDeleteWorld_Click(object sender, EventArgs e) {
            WorldList[GetWorldIndex((string)listBox1.SelectedItem)] = null;
            SelectedWorld = 0;
            RefreshForm();
        }

        private void buttonSaveWorld_Click(object sender, EventArgs e) {
            SaveChanges();
            this.Close();
        }

        private void buttonLoadCharacter_Click(object sender, EventArgs e) {
            if (textBoxCharacterName.Text == "" // Check for empties!
                && textBoxCharacterPassword.Text == ""
                && mEditingCharacter == null) {
                    foreach (Character c in WorldList[SelectedWorld].Characters) {
                        if (c.Name == (string)dataGridView1.SelectedRows[0].Cells[0].Value) { // We found the name.
                            mEditingCharacter = c;
                            break;
                        }
                    }
                // Okay to load character
                    textBoxCharacterName.Text = mEditingCharacter.Name;
                    textBoxCharacterPassword.Text = mEditingCharacter.Password;
                    checkBoxAutoConnect.Checked = mEditingCharacter.AutoConnect;
                    checkBoxDefaultCharacter.Checked = mEditingCharacter.IsDefault;
            } else {
                // Oh no! We're trying to load a character over something already up.
                // Confirm the user is sure they want to do this.
            }
        }

        private void buttonSaveCharacter_Click(object sender, EventArgs e) {
            VerifyChanges();
            if (textBoxCharacterName.Text != "" // Check for empties!
                && textBoxCharacterPassword.Text != "") {
                    if (checkBoxDefaultCharacter.Checked) // Clear any other 'default' characters. There can be only one.
                        foreach (Character c in WorldList[SelectedWorld].Characters)
                            c.IsDefault = false;
                // Remove old character.
                    if (mEditingCharacter != null) {
                        WorldList[SelectedWorld].Characters.Remove(mEditingCharacter);
                        mEditingCharacter = null;
                    }
                // Write the new character data.
                Console.WriteLine("Caching Character: " + textBoxCharacterName.Text);
                    WorldList[SelectedWorld].Characters.Add(new Character() {
                        Name = textBoxCharacterName.Text,
                        Password = textBoxCharacterPassword.Text,
                        IsDefault = checkBoxDefaultCharacter.Checked,
                        AutoConnect = checkBoxAutoConnect.Checked
                    });
                // Clear the form to show we saved it. Update character panel.
                    textBoxCharacterName.Text = "";
                    textBoxCharacterPassword.Text = "";
                    checkBoxAutoConnect.Checked = false;
                    checkBoxDefaultCharacter.Checked = false;
                    RefreshCharacterList();
            }
        }

        private void buttonCancelChanges_Click(object sender, EventArgs e) {
            // Check for changes
            if (true &&
                MessageBox.Show("Changes bluh", "Bluh", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) {
                this.Close();
            } else {
                this.Close();
            }
        }

        private void textBox_Leave(object sender, EventArgs e) {
            if (textBoxWorldName.Text != WorldList[SelectedWorld].WorldName) { // Name update!
                bool duplicateName = false;
                foreach (WorldConfig wc in WorldList) {
                    if(wc != WorldList[SelectedWorld]) // Don't check if the world is the same one we're editing.
                        if (wc.WorldName == textBoxWorldName.Text) { // Duplicate name?
                            duplicateName = true;
                            MessageBox.Show("A world with a duplicate name exists. Unable to change world name.",
                                "Duplicate World Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            textBoxWorldName.Text = WorldList[SelectedWorld].WorldName;
                        }
                }

                // No duplicate names. Can set.
                if(!duplicateName)
                    WorldList[SelectedWorld].WorldName = textBoxWorldName.Text;
                RefreshWorldList();
            }
            VerifyChanges();
        }

        private void checkBoxCheckStateChanged(object sender, EventArgs e) {
            VerifyChanges();
        }

        private void checkBoxUnhidePasswords_CheckStateChanged(object sender, EventArgs e) {
            RefreshCharacterList();
            textBoxCharacterPassword.UseSystemPasswordChar = !checkBoxUnhidePasswords.Checked;
        }

        private void VerifyChanges() {
            WorldList[SelectedWorld].ChangesMade = true;
        }
        #endregion

        private Character mEditingCharacter;
    }
}
